#
#   =======================================================================
#
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#   1 Redistributions of source code must retain the above copyright notice,
#     this list of conditions and the following disclaimer.
#
#   2 Redistributions in binary form must reproduce the above copyright notice,
#     this list of conditions and the following disclaimer in the documentation
#     and/or other materials provided with the distribution.
#
#   3 Neither the names of the copyright holders nor the names of the
#   contributors may be used to endorse or promote products derived from this
#   software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#   =======================================================================
#
'''common installation'''
import os
import platform
import signal
import subprocess
import time
import sys

# todo print need to change to logger.

class MakeSDCardProxy:
    def __init__(self, working_path, log_file, log_result, eth0_ip=None, usb_ip=None, sudo_passwd=None, mylogger=None):
        parent_dir = os.path.dirname(os.path.abspath(__file__))
        NETWORK_CARD_DEFAULT_IP = eth0_ip
        USB_CARD_DEFAULT_IP = usb_ip

        # VERSION_INFO_URL = "https://raw.githubusercontent.com/Ascend/tools/master/versioninfo.yaml"

        # CURRENT_PATH = os.path.dirname(
        #     os.path.realpath(__file__))

        self.logger = mylogger

        self.CURRENT_PATH = working_path
        self.log_file = log_file
        print(log_file)

        self.log_result = log_result

        self.SD_CARD_MAKING_PATH = os.path.join(self.CURRENT_PATH, "sd_card_making")

        self.MIN_DISK_SIZE = 7 * 1024 * 1024 * 1024

        # MAKING_SD_CARD_COMMAND = "bash {path}/make_ubuntu_sd.sh " + " {dev_name}" + \
        #     " {pkg_path} {ubuntu_file_name} {ascend_developerkit_file_name}" + \
        #     " " + NETWORK_CARD_DEFAULT_IP + " " + USB_CARD_DEFAULT_IP + \
        #     " > {log_path}/make_ubuntu_sd.log "

        self.sudo_passwd = sudo_passwd

        print(self.log_file)

        self.MAKING_SD_CARD_COMMAND = "cd {path}; echo " + self.sudo_passwd + " | sudo -S bash {path}/make_ubuntu_sd.sh " + " {dev_name}" + \
            " {pkg_path} {ubuntu_file_name} {ascend_developerkit_file_name}" + \
            " " + NETWORK_CARD_DEFAULT_IP + " " + USB_CARD_DEFAULT_IP + \
            " >> " + str(self.log_file)
        self.MAKING_SD_CARD_COMMAND_x = "cd {path}; echo " + 'passwd' + " | sudo -S bash {path}/make_ubuntu_sd.sh " + " {dev_name}" + \
                                      " {pkg_path} {ubuntu_file_name} {ascend_developerkit_file_name}" + \
                                      " " + NETWORK_CARD_DEFAULT_IP + " " + USB_CARD_DEFAULT_IP + \
                                      " >> " + str(self.log_file)

        self.logger.info(self.MAKING_SD_CARD_COMMAND_x)

    def execute(self, cmd, timeout=3600, cwd=None):
        '''execute os command'''
        # print(cmd)
        is_linux = platform.system() == 'Linux'

        if not cwd:
            cwd = os.getcwd()
        process = subprocess.Popen(cmd, cwd=cwd, bufsize=32768, stdout=subprocess.PIPE,
                                   stderr=subprocess.STDOUT, shell=True,
                                   preexec_fn=os.setsid if is_linux else None)

        t_beginning = time.time()

        # cycle times
        time_gap = 0.01

        str_std_output = ""
        while True:

            str_out = str(process.stdout.read().decode())

            str_std_output = str_std_output + str_out

            if process.poll() is not None:
                break
            seconds_passed = time.time() - t_beginning

            if timeout and seconds_passed > timeout:

                if is_linux:
                    os.kill(process.pid, signal.SIGTERM)
                else:
                    process.terminate()
                return False, process.stdout.readlines()
            time.sleep(time_gap)
        str_std_output = str_std_output.strip()
        # print(str_std_output)
        std_output_lines_last = []
        std_output_lines = str_std_output.split("\n")
        for i in std_output_lines:
            std_output_lines_last.append(i)

        if process.returncode != 0 or "Traceback" in str_std_output:
            return False, std_output_lines_last

        return True, std_output_lines_last

    def print_process(self, string, is_finished=False):
        if string == "" or string is None or is_finished:
            self.logger.info(".......... .......... .......... .......... 100%", end='\r')
            self.logger.info("")
        else:
            string = string.split(".......... ", 1)[1]
            string = string.split("%")[0] + "%"
            self.logger.info(string, end='\r')

    def check_sd(self, dev_name):

        command_str = 'echo '+ self.sudo_passwd + " | sudo -S fdisk -l 2>/dev/null | grep \"Disk {dev_name}:\"".format(dev_name=dev_name)
        command_str_x = 'echo '+ 'passwd' + " | sudo -S fdisk -l 2>/dev/null | grep \"Disk {dev_name}:\"".format(dev_name=dev_name)

        self.logger.info(command_str_x)
        ret, disk = self.execute(command_str)

        if not ret or len(disk) > 1:
            self.logger.info(
                "[ERROR] Can not get disk, please use fdisk -l to check available disk name!")
            return False

        ret, mounted_list = self.execute('echo '+ self.sudo_passwd + " | sudo -S df -h")

        if not ret:
            self.logger.info("[ERROR] Can not get mounted disk list!")
            return False

        unchanged_disk_list = []
        for each_mounted_disk in mounted_list:
            disk_name = each_mounted_disk.split()[0]
            disk_type = each_mounted_disk.split()[5]
            if disk_type == "/boot" or disk_type == "/":
                unchanged_disk_list.append(disk_name)
        unchanged_disk = " ".join(unchanged_disk_list)

        disk_size_str = disk[0].split(", ")[1]
        disk_size_str = disk_size_str.split()[0]
        disk_size = int(disk_size_str)

        if dev_name not in unchanged_disk and disk_size >= self.MIN_DISK_SIZE:
            return True

        self.logger.info("[ERROR] Invalid SD card or size is less then 8G, please check SD Card.")
        return False



    def process_local_installation(self, dev_name):
        # confirm_tips = "Please make sure you have installed dependency packages:" + \
        #     "\n\t apt-get install -y qemu-user-static binfmt-support gcc-aarch64-linux-gnu g++-aarch64-linux-gnu\n" + \
        #     "Please input Y: continue, other to install them:"
        # confirm = input(confirm_tips)
        # confirm = confirm.strip()
        #
        # if confirm != "Y" and confirm != "y":
        #     return False

        self.execute('echo '+ self.sudo_passwd + " | sudo -S rm -rf {path}_log/*".format(path=self.SD_CARD_MAKING_PATH))
        self.execute('echo '+ self.sudo_passwd + "| sudo -S mkdir -p {path}_log".format(path=self.SD_CARD_MAKING_PATH))
        log_path = "{path}_log".format(path=self.SD_CARD_MAKING_PATH)
        ret, paths = self.execute(
            'echo '+ self.sudo_passwd + " | sudo -S find {path} -name \"mini_developerkit*.rar\"".format(path=self.CURRENT_PATH))
        if not ret:
            self.logger.info("[ERROR] Can not fine mini eveloperkit package in current path")
            return False

        if len(paths) > 1:
            self.logger.info(
                "[ERROR] Too many mini developerkit packages, please delete redundant packages.")
            return False
        ascend_developerkit_path = paths[0]
        ascend_developerkit_file_name = os.path.basename(ascend_developerkit_path)

        ret, paths = self.execute(
            'echo '+ self.sudo_passwd + " | sudo -S find {path} -name \"make-ubuntu-sd.sh\"".format(path=self.CURRENT_PATH))
        if not ret:
            self.logger.info("[ERROR] Can not fine make_ubuntu_sd.sh in current path")
            return False

        ret, paths = self.execute(
            'echo '+ self.sudo_passwd + " | sudo -S find {path} -name \"ubuntu*server*arm*.iso\"".format(path=self.CURRENT_PATH))
        if not ret:
            self.logger.info("[ERROR] Can not fine ubuntu\ package in current path")
            return False
        if len(paths) > 1:
            self.logger.info("[ERROR] Too many ubuntu packages, please delete redundant packages.")
            return False
        ubuntu_path = paths[0]
        ubuntu_file_name = os.path.basename(ubuntu_path)

        self.logger.info("Step: Start to make SD Card. It need some time, please wait...")

        command_str = self.MAKING_SD_CARD_COMMAND.format(path=self.CURRENT_PATH, dev_name=dev_name, pkg_path=self.CURRENT_PATH,
                                                    ubuntu_file_name=ubuntu_file_name,
                                                    ascend_developerkit_file_name=ascend_developerkit_file_name, log_path=log_path)

        self.logger.info(command_str)
        # self.execute(command_str)


        self.execute(self.MAKING_SD_CARD_COMMAND.format(path=self.CURRENT_PATH, dev_name=dev_name, pkg_path=self.CURRENT_PATH,
                                                    ubuntu_file_name=ubuntu_file_name,
                                                    ascend_developerkit_file_name=ascend_developerkit_file_name, log_path=log_path))
        ret = self.execute('echo '+ self.sudo_passwd + " | sudo -S grep Success {log_path}/make_ubuntu_sd.result".format(log_path=log_path))
        if not ret[0]:
            self.logger.error("[ERROR] Making SD Card failed, please check %s/make_ubuntu_sd.log for details!" % log_path)
            return False

        return True


#
# def print_usage():
#     self.logger.info("Usage: ")
#     self.logger.info("\t[internet]: python3 make_sd_card.py internet [SD Name]")
#     print("\t                 Use latest version to make SD card.")
#     print("\t[internet]: python3 make_sd_card.py internet [SD Name] [Version]")
#     print("\t                 Use given version to make SD card.")
#     print("\t[local   ]: python3 make_sd_card.py local [SD Name]")
#     print("\t                 Use local given packages to make SD card.")


def main():
    '''sd card making'''
    command = "local"
    dev_name = "/dev/sdb"

    # if (len(sys.argv) >= 4):
    #     command = sys.argv[1]
    #     dev_name = sys.argv[2]
    #     log_file = sys.argv[3]
    #
    # # if (len(sys.argv) >= 4):
    # #     version = sys.argv[3]
    #
    # if command == "local" and len(sys.argv) == 4:
    #     print("Begin to make SD Card...")
    # else:
    #     print("Invalid Command!")
    #     print_usage()
    #     exit(-1)

    # CURRENT_PATH = os.path.dirname(os.path.realpath(__file__))
    CURRENT_PATH = os.path.dirname(os.path.abspath(sys.argv[0]))
    working_path = os.path.join(CURRENT_PATH, "makesd")
    log_file = os.path.join(CURRENT_PATH, 'makesdcard.log')
    log_result = os.path.join(CURRENT_PATH, 'makesdcard.result')

    make_sd_card_proxy = MakeSDCardProxy(working_path, log_file, log_result)

    ret = make_sd_card_proxy.check_sd(dev_name)

    if not ret:
        exit(-1)

    result = make_sd_card_proxy.process_local_installation(dev_name)

    if result:
        print("Make SD Card successfully!")
        exit(0)
    else:
        exit(-1)


if __name__ == '__main__':
    main()
